//!
/**
 ***********************************************************************************************************
 * <RBHardwareBufferManager Implementation>
 ***********************************************************************************************************
 * @file RBHardwareBufferManager.cpp
 ***********************************************************************************************************/

/***********************************************************************************************************
 * Precompiled Header
 ***********************************************************************************************************/
#include "RBMainPCH.h"

/***********************************************************************************************************
 * Includes
 ***********************************************************************************************************/
#include "RBHardwareBufferManager.h"

#include "RBIndexBuffer.h"
#include "RBResourceManager.h"
#include "RBTexture.h"
#include "RBVertexDeclaration.h"
#include "RBVertexBuffer.h"
#include "RBVertexElement.h"

/***********************************************************************************************************
 * Defines
 ***********************************************************************************************************/

/***********************************************************************************************************
 * Classes implementation
 ***********************************************************************************************************/

/**
 ***********************************************************************************************************
 * Constructor
 ***********************************************************************************************************/
RBHardwareBufferManager::RBHardwareBufferManager()
{
}

/**
 ***********************************************************************************************************
 * Destructor
 ***********************************************************************************************************/
RBHardwareBufferManager::~RBHardwareBufferManager()
{
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
void RBHardwareBufferManager::AddBuffer(RBHardwareBuffer* pBuffer)
{
    m_aAllocatedBuffers.push_back(pBuffer);
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
void RBHardwareBufferManager::RemoveBuffer(RBHardwareBuffer* pBuffer)
{
    m_aAllocatedBuffers.remove(pBuffer);
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
void RBHardwareBufferManager::Write(RBVertexDeclaration* pVertexDecl, RBStream& kStream)
{
    //Save Vertex Declaration: we suppose atm that we don't shader Vertex Declaration among VertexData
    kStream << pVertexDecl->GetElementCount();
    RBVertexElement* pElements = pVertexDecl->GetElements();

    for (uint32 uiElement = 0; uiElement < pVertexDecl->GetElementCount(); ++uiElement)
    {
        pElements[uiElement].Save(kStream);
    }
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
void RBHardwareBufferManager::Write(RBVertexBuffer* pVertexBuffer, RBStream& kStream)
{
    kStream << pVertexBuffer->GetVertexSize() << pVertexBuffer->GetVertexCount() << pVertexBuffer->GetUsage();

    void* pMappedVB = pVertexBuffer->Map(rb_hw_buffer_usage::HBM_READ_ONLY);
    kStream.WriteBuffer(pMappedVB, pVertexBuffer->GetVertexSize() * pVertexBuffer->GetVertexCount());
    pVertexBuffer->Unmap();
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
void RBHardwareBufferManager::Write(RBIndexBuffer* pIndexBuffer, RBStream& kStream)
{
    RBIndexBufferType::EType eIdxType = pIndexBuffer->GetIndexType();
    kStream << eIdxType << pIndexBuffer->GetIndexCount() << pIndexBuffer->GetUsage();

    uint8 uiIdxSize = (eIdxType == RBIndexBufferType::IT_16BIT) ? 2 : 4;

    void* pMappedIB = pIndexBuffer->Map(rb_hw_buffer_usage::HBM_READ_ONLY);
    kStream.WriteBuffer(pMappedIB, uiIdxSize * pIndexBuffer->GetIndexCount());
    pIndexBuffer->Unmap();

}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
void RBHardwareBufferManager::Write( RBTexture* /*pTexture*/, RBStream& kStream )
{
    uint32 uiIsSource = 0;//pTexture->IsSourceTexture();
    
    kStream << uiIsSource;

/*
    if (pTexture->IsSourceTexture())
    {
        kStream.Write(pTexture->GetFilename());
    }
*/
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBVertexDeclaration* RBHardwareBufferManager::ReadVertexDeclaration(RBStream& kStream)
{
    uint32 uiElementCount;
    kStream >> uiElementCount;
    RBVertexElement* pElements = new RBVertexElement[uiElementCount];

    for (uint32 uiElement = 0; uiElement < uiElementCount; ++uiElement)
    {
        pElements[uiElement].Load(kStream);
    }

    RBVertexDeclaration* pVertexDecl = CreateVertexDeclaration(pElements, uiElementCount, NULL);

    return pVertexDecl;

}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBVertexBuffer* RBHardwareBufferManager::ReadVertexBuffer(RBStream& kStream)
{
    uint32 uiVtxSize, uiVtxCount, uiUsage;
    kStream >> uiVtxSize >> uiVtxCount >> uiUsage;

    char* pBuffer = new char[uiVtxSize*uiVtxCount];
    kStream.ReadBuffer(pBuffer, uiVtxSize*uiVtxCount);

    RBVertexBuffer* pVertexBuffer = CreateVertexBuffer(uiUsage, uiVtxSize, uiVtxCount, pBuffer);

    delete[] pBuffer;

    return pVertexBuffer;

}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
RBIndexBuffer* RBHardwareBufferManager::ReadIndexBuffer(RBStream& kStream)
{
    RBIndexBufferType::EType eIdxType;
    uint32 uiIdxCount, uiUsage;
    kStream >> eIdxType >> uiIdxCount >> uiUsage;

    uint8 uiIdxSize = (eIdxType == RBIndexBufferType::IT_16BIT) ? 2 : 4;
    char* pBuffer = new char[uiIdxSize * uiIdxCount];
    kStream.ReadBuffer(pBuffer, uiIdxSize * uiIdxCount);

    RBIndexBuffer* pIndexBuffer = CreateIndexBuffer(uiUsage, eIdxType, uiIdxCount, pBuffer);

    delete[] pBuffer;

    return pIndexBuffer;
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBTexture* RBHardwareBufferManager::ReadTexture( RBStream& kStream )
{
    uint32 uiIsSource;

    kStream >> uiIsSource;

    if (uiIsSource)
    {
        RBString strFilename;
        kStream.Read(strFilename);
        return RBResourceManager::GetSingleton()->GetTexture(strFilename);
    }

    return 0;
}

void RBHardwareBufferManager::CreateRenderTarget( uint32 uiWidth, uint32 uiHeight, RBPixelFormat eRenderFormat, uint32 uiMSAA, RBTexture** pTexture, 
                                                  RBRenderTargetView** pRTT, RBShaderResourceView** pShaderView, RBPixelFormat eTextureFormat )
{
    uint32 uiFlags = rb_hw_buffer_usage::HBU_RENDER_TARGET;
    if (pShaderView != NULL)
    {
        uiFlags |= rb_hw_buffer_usage::HBU_SHADER_RESOURCE;
    }
    
    *pTexture = CreateRenderTarget(uiFlags, uiWidth, uiHeight, eRenderFormat, uiMSAA);

    if (*pTexture && pRTT)
    {
        *pRTT = CreateRenderTargetView(*pTexture);
    }

    if (*pTexture && pShaderView)
    {
        *pShaderView = CreateShaderResourceView(*pTexture, eTextureFormat);
    }
}
/***********************************************************************************************************/
